﻿using System;
using System.Text;
using log4net.Appender;
using log4net.Core;
using log4net.Layout;
using System.IO;
using log4net.Util;
using log4net.Layout.Pattern;
using System.Reflection;

namespace HS.Log
{
    #region Appender
    /// <summary>  
    /// 
    /// </summary>
    /// <author></author>
    internal class FileAppender : AppenderSkeleton
    {
        public FileAppender()
        {
        }

        public PatternLayout File { get; set; }


        public Encoding Encoding { get; set; } = Encoding.Default;


        public SecurityContext SecurityContext { get; set; }


        override public void ActivateOptions()
        {
            base.ActivateOptions();

            if (SecurityContext == null)
            {
                SecurityContext = SecurityContextProvider.DefaultProvider.CreateSecurityContext(this);
            }
        }

        override protected void Append(LoggingEvent loggingEvent)
        {
            try
            {
                // Render the file name
                string fileName = GetFilePath(loggingEvent);
                FileStream fileStream = null;
                using (SecurityContext.Impersonate(this))
                {
                    // Ensure that the directory structure exists
                    string directoryFullName = Path.GetDirectoryName(fileName);

                    // Only create the directory if it does not exist
                    // doing this check here resolves some permissions failures
                    if (!Directory.Exists(directoryFullName))
                    {
                        Directory.CreateDirectory(directoryFullName);
                    }

                    // Open file stream while impersonating
                    fileStream = new FileStream(fileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
                }

                if (fileStream != null)
                {
                    using (StreamWriter streamWriter = new StreamWriter(fileStream, Encoding))
                    {
                        RenderLoggingEvent(streamWriter, loggingEvent);
                    }

                    fileStream.Close();
                }
            }
            catch (Exception ex)
            {
                ErrorHandler.Error("Failed to append to file", ex);
            }
        }

        protected virtual string GetFilePath(LoggingEvent loggingEvent)
        {
            StringWriter stringWriter = new StringWriter();
            File.Format(stringWriter, loggingEvent);
            string fileName = stringWriter.ToString();
            fileName = SystemInfo.ConvertToFullPath(fileName);
            return fileName;
        }
    }
    #endregion
}
